<template>
  <div :class="disabled ? 'disabled' : ''">
    <el-upload
      ref="uploadRef"
      :disabled="disabled"
      :list-type="listType"
      action="#"
      :file-list="elList"
      :show-file-list="true"
      :on-exceed="onExceed"
      :auto-upload="false"
      :on-change="onChange"
      :before-upload="addbeforeupload"
      :before-remove="beforeRemove"
      :limit="limit * 1"
      :multiple="limit > 1 ? true : false"
      :accept="accept"
    >
      <i slot="default" class="el-icon-plus"></i>
      <div v-if="!disabled" slot="tip" class="el-upload__tip">
        只能上传{{ getAccept(accept) }}文件，且不超过{{ size }}mb
      </div>
      <!-- <el-button v-if="'picture-card' !== listType" slot="trigger" size="small" type="primary">
        <i class="el-icon-plus"></i>选取文件
       </el-button> -->
      <div slot="file" slot-scope="{ file }">
        <div>
          <div>
            <!-- 图片展示 -->
            <div v-show="file.status === 'success'">
              <y-show-all-file :ref="'ref_' + file.name" class="el-upload-list__item-thumbnail" :path="file.url" />
            </div>
            <!-- 失败展示 -->
            <div v-if="file.status === 'fail'" class="el-upload-list__item-thumbnail up-type">
              <i class="el-icon-error" style="font-size: 50px; color: tomato"></i>
              <div>
                {{ file.name }}
              </div>
            </div>
            <!-- 上传中展示 -->
            <el-progress v-else-if="file.status === 'uploading'" type="circle" :percentage="0"></el-progress>
            <span class="el-upload-list__item-actions">
              <span
                v-if="file.status === 'success'"
                class="el-upload-list__item-preview"
                @click="handlePictureCardPreview(file)"
              >
                <i class="el-icon-zoom-in"></i>
              </span>
              <span v-if="!disabled" @click="onRemoveFile(file)" class="el-upload-list__item-delete">
                <i class="el-icon-delete"></i>
              </span>
            </span>
          </div>
        </div>
      </div>
    </el-upload>
    <y-show-file ref="showFile" />
  </div>
</template>

<script>
import OssClient from '@/utils/ossClient'
import { getHttpURL } from '@/utils/fileUtils.js'
import Compressor from 'compressorjs'
import YShowFile from '@/components/YShowFile'

export default {
  components: { YShowFile },
  props: {
    disabled: {
      type: Boolean,
      default: false
    },
    // 允许上传的文件类型
    accept: {
      type: String,
      default: '.png,.jpg,.jpeg,.gif,.pdf,.doc,.docx'
    },
    // 上传文件大小限制（MB）
    size: {
      type: String,
      default: '10'
    },
    // 上传文件个数限制
    limit: {
      type: String,
      default: '1'
    },
    // 上传文件的文件夹
    folder: {
      type: String,
      default: '/profile'
    },
    // 上传文件的分类文件夹
    type: {
      type: String,
      default: '/common'
    },
    // 上传描述
    // tip: {
    //     type: String,
    //     default: "只能上传jpg/png文件，且不超过2mb"
    // },
    // 文件列表的类型
    listType: {
      type: String,
      default: 'picture-card'
    },
    // word转pdf
    wordToPdf: {
      type: Boolean,
      default: false
    },
    // 展示的文件列表
    path: {
      type: Array | String,
      default: () => []
    }
  },
  // 监听fileList
  watch: {
    pathList: {
      handler: function (val) {
        this.fileList = val
      },
      deep: true
    },
    path: {
      handler: function (val, old) {
        if (JSON.stringify(val) != JSON.stringify(old) && val) {
          this.getFileShow()
        }
      },
      deep: true
    }
  },
  pathList() {
    let path = []
    if (this.path instanceof Array) {
      path = this.path
    } else {
      path = this.path.split(',')
    }
    return path
  },
  data() {
    return {
      dialogImageUrl: '',
      dialogVisible: false,
      fileList: [],
      elList: [],
      oss: null
    }
  },
  created() {
    // oss初始化
    this.oss = new OssClient()
    this.getFileShow()
  },
  methods: {
    // 判断是否要展示文件
    getFileShow() {
      this.elList = []

      if (this.path instanceof Array && this.path[0]) {
        this.path.map((item) => {
          if (item) this.elList.push({ name: item, url: getHttpURL(item), status: 'success' })
        })
      } else if (typeof this.path === 'string' && this.path) {
        const list = this.path.split(',')
        list.map((item) => {
          if (item) this.elList.push({ name: item, url: getHttpURL(item), status: 'success' })
        })
      } else if (!this.path[0]) {
        this.clearFiles()
      }
    },
    getAccept(v) {
      let a = v.replaceAll(',.', '/')
      return a.replaceAll('\.', '')
    },
    // 判断文件类型是否可预览
    isPreview(file) {
      let fileType = this.getFileType(file)
      const typeArr = ['pdf', 'jpg', 'jpeg', 'png', 'gif']
      if (typeArr.indexOf(fileType) !== -1) {
        return true
      }
      return false
    },
    // 判断文件是否是图片
    isImage(file) {
      let fileType = this.getFileType(file)
      const typeArr = ['jpg', 'jpeg', 'png', 'gif']
      if (typeArr.indexOf(fileType) !== -1) {
        return true
      }
      return false
    },
    // 判断文件是否是word
    isWord(file) {
      let fileType = this.getFileType(file)
      const typeArr = ['doc', 'docx']
      if (typeArr.indexOf(fileType) !== -1) {
        return true
      }
      return false
    },
    // 获取文件后缀
    getFileType(file) {
      let arr = file.url.split('.')
      let fileType = arr[arr.length - 1].toLowerCase()
      return fileType
    },

    // 文件删除
    onRemoveFile(file) {
      const index = this.$refs.uploadRef.uploadFiles.findIndex((e) => e.uid === file.uid)
      this.beforeRemove(file).then((res) => {
        this.$refs.uploadRef.uploadFiles.splice(index, 1)
      })
    },
    // 放大
    handlePictureCardPreview(file) {
      if (this.isPreview(file)) {
        this.$refs.showFile.open(file)
      } else {
        this.$refs['ref_' + file.name].open(file.url)
      }
    },
    // 文件超出个数限制时的钩子
    onExceed(file, fileList) {
      this.$message.error('只允许上传' + this.limit + '个文件')
    },
    // 文件添加时回调
    onChange(file, fileList, scope) {
      if (!this.addbeforeupload(file)) {
        const index = this.getFileIndexByVal(fileList, file)
        // 取消上传
        fileList.splice(index, 1)
        return
      }
      // 获取文件后缀
      const arr = file.name.split('.')
      const suffix = arr[arr.length - 1]
      // 判断文件类型，是否允许上传
      if (this.accept.indexOf(suffix) === -1) {
        this.$message.error('文件类型不允许上传')
        return false
      }
      // 如果是word文件，判断是否需要转pdf
      if (this.wordToPdf && this.isWord(file)) {
        this.$message.error('暂不支持docx文件上传')
        return false
      }
      this.uploadFile(file)
    },

    // 判断文件大小
    addbeforeupload(file) {
      const isLt2M = file.size / 1024 / 1024 < this.size
      if (!isLt2M) {
        this.$message.error('上传文件大小不能超过 ' + this.size + 'MB!')
      }
      return isLt2M
    },

    // 删除前的钩子
    beforeRemove(file, fileList) {
      let that = this
      return that.$confirm(`确定移除`).then((res) => {
        console.log('删除1')
        that.fileList = that.removeFileByVal(that.fileList, 'uid', file.uid)
        this.$emit('onChange', that.fileList)
        this.$message({
          type: 'success',
          message: '删除成功!'
        })
      })
    },
    // 基于fileList的指定key删除数组中的元素
    removeFileByVal(list, key, v) {
      return list.filter((item) => {
        return item[key] !== v
      })
    },
    // 基于fileList的指定key返回index
    getFileIndexByVal(list, key, v) {
      return list.findIndex((item) => item[key] === v)
    },
    // 上传文件
    async uploadFile(file) {
      // 将文件状态改为上传中
      file.status = 'uploading'
      // 获取文件后缀
      const f = file.name.split('.')
      // 文件上传，文件名 = 文件夹 + 文件名 + uid + 后缀
      let row = file.raw
      // 图片全部走压缩
      if (this.isImage(file)) {
        row = await new Promise((resolve, reject) => {
          new Compressor(file.raw, {
            quality: 0.6,
            success(result) {
              resolve(result)
            },
            error(error) {
              reject(error)
            }
          })
        })
      }

      this.oss
        .put(this.getFolder() + f[0] + '_' + file.uid + '.' + f[f.length - 1], row)
        .then((res) => {
          // 将上传成功的文件信息存入fileList
          this.fileList.push({
            name: res.name,
            uid: file.uid,
            router: this.getRouter(res.url),
            domain: this.getDomain(res.url),
            url: res.url
          })
          file.url = res.url
          // this.elList.push({name: file.name, url: res.url})
          file.status = 'success'
          // 将fileList传出
          this.$emit('onChange', this.fileList)
          this.$emit('onSuccess', this.fileList[this.fileList.length - 1], this.fileList)
        })
        .catch((err) => {
          console.log(err)
          this.$message.error(err)
          file.status = 'fail'
        })
    },

    // 获取上传文件将
    getFolder() {
      let folder = this.folder + '/' + this.type
      // 将年月日作为文件夹
      const date = new Date()
      const year = date.getFullYear()
      const month = date.getMonth() + 1
      const day = date.getDate()
      folder = folder + '/' + year + '/' + month + '/' + day + '/'
      // 将所有// 替换为 /
      folder = folder.replace(/\/\//g, '/')
      return folder
    },
    // 根据url获取域名
    getDomain(url) {
      return url.match(/^https?:\/\/[^/]+/)[0]
    },
    // 根据传入的网址 返回路由
    getRouter(url) {
      let domain = url.match(/^https?:\/\/[^/]+/)[0]
      return url.replace(domain, '')
    },
    // 清除上传列表
    clearFiles() {
      if (this.$refs.uploadRef) this.$refs.uploadRef.clearFiles()
      else {
        this.$nextTick(() => {
          this.$refs.uploadRef.clearFiles()
        })
      }
    }
  }
}
</script>
<style>
.disabled .el-upload--picture-card {
  display: none !important;
}
</style>
<style scoped>
.up-type {
  position: absolute;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}
</style>
